import asyncio
import os
#os.environ['ALSA_DEBUG'] = '0'
#os.environ['ALSA_CONF'] = '/dev/null'

from aiortc_custom.logger_config import log_info, log_debug, log_warning, log_error, log_success, log_failure, log_progress, log_connection, log_media, log_stats, log_fec, log_fec_success, log_fec_error, log_fec_config
import cv2
import time
import signal
from aiortc_custom import (
    RTCSessionDescription,
    RTCConfiguration,
    RTCIceServer,
    RTCIceCandidate,
    RTCPeerConnection
)
from VideoStreamTrack import TimedVideoStreamTrack
from AudioStreamTrackCustom import FileAudioStreamTrack, MicrophoneAudioStreamTrack
# 视频预览模块
from VideoPreManager import VideoPreviewManager
from VideoReceiver import VideoReceiver
from AudioReceiver import AudioReceiver
from signaling import WebSocketSignaling
import random
from aiortc_custom.fec import FecConfig
from aiortc_custom.rtcrtpparameters import RTCRtpDecodingParameters
from fec_controller import FecController, FecControlConfig
from fec_configuration import configure_receivers_with_fec, configure_senders_with_fec, display_fec_selection_menu, parse_fec_choice


# 全局变量用于优雅关闭
shutdown_event = asyncio.Event()

def signal_handler(signum, frame):
    """信号处理器，用于优雅关闭"""
    log_info("\n收到信号 {signum}，正在关闭...", signum=signum)
    shutdown_event.set()

# 注册信号处理器
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

async def run_peer(is_offering, server_url, client_id, peer_id, video_source, fec_type="repetition", fec_k=2, fec_n=4):
    # 记录开始时间
    start_time = time.time()
    
    # 创建视频预览管理器
    preview_manager = VideoPreviewManager()
    
    # 创建FEC控制器
    fec_controller = FecController()
    
    signaling = None
    pc = None
    stats_task = None
    
    try:
        signaling = WebSocketSignaling(server_url, client_id)
        signaling.peer_id = peer_id
        config = RTCConfiguration()
        config.iceServers = [
            RTCIceServer(
                urls=["stun:stun.l.google.com:19302"]
            ),    
            RTCIceServer(
                urls=["turn:120.79.253.49:3479"],
                username="9ian9",
                credential="666"
            )
        ]
        
        pc = RTCPeerConnection(configuration=config)
        
        # 启用FEC功能
        if fec_type:
            fec_controller.enable_fec(fec_type, k=fec_k, n=fec_n)
            fec_config = fec_controller.get_fec_config()
            log_fec_success("FEC已启用: {fec_type}, k={k}, n={n}", 
                           fec_type=fec_config.fec_type if fec_config else "无", 
                           k=fec_config.k if fec_config else 0, 
                           n=fec_config.n if fec_config else 0)
        else:
            fec_controller.disable_fec()
            log_fec("FEC已禁用")
        
        log_progress("初始化视频轨道...")
        video_sender = TimedVideoStreamTrack(video_source, preview_manager)
        # 确保视频源初始化成功后再添加轨道
        if video_sender.cap is not None and video_sender.cap.isOpened():
            pc.addTrack(video_sender)
            log_success("已添加视频发送轨道 ")
        else:
            log_failure("视频源初始化失败，无法添加视频轨道")
            raise RuntimeError("视频源初始化失败")

        # 音频轨道：如果是文件且包含音频，则添加文件音频；如果是摄像头，则尝试使用默认麦克风
        try:
            audio_track = None
            if isinstance(video_source, int):
                log_progress("初始化麦克风音频轨道...")
                audio_track = MicrophoneAudioStreamTrack()
            else:
                # 尝试从视频文件中提取音频
                import os
                if isinstance(video_source, str) and os.path.exists(video_source):
                    try:
                        audio_track = FileAudioStreamTrack(video_source)
                        log_success("检测到文件包含音频流，已添加音频发送轨道")
                    except Exception as e:
                        log_info("未添加文件音频流: {e}", e=e)
                else:
                    # 默认文件路径
                    default_video_path = "time.mp4"
                    if os.path.exists(default_video_path):
                        try:
                            audio_track = FileAudioStreamTrack(default_video_path)
                            log_success("默认文件包含音频流，已添加音频发送轨道")
                        except Exception as e:
                            log_info("默认文件音频流不可用: {e}", e=e)

            if audio_track is not None:
                pc.addTrack(audio_track)
                log_success("已添加音频发送轨道")
            else:
                log_info("未添加音频发送轨道（无可用音频源）")
        except Exception as e:
            log_info("初始化音频轨道失败: {e}", e=e)
        
        video_receiver = VideoReceiver(preview_manager)
        video_receiver.set_peer_connection(pc)
        
        # 音频接收器
        audio_receiver = AudioReceiver()
        audio_receiver.set_peer_connection(pc)


        @pc.on("track")
        def on_track(track):
            log_success("收到远程轨道: {track_kind}", track_kind=track.kind)
            #log_debug("轨道详细信息 - kind={track.kind}, id={getattr(track, 'id', 'N/A')}", track_kind=track.kind, getattr(track, 'id', 'N/A')=getattr(track, 'id', 'N/A'))
            #log_debug("轨道状态 - readyState={getattr(track, 'readyState', 'N/A')}", getattr(track, 'readyState', 'N/A')=getattr(track, 'readyState', 'N/A'))
            
            if track.kind == "video":
                #log_success("开始处理接收的远程视频轨道...")

                log_success("正在启动远程视频预览...")
                # 使用VideoReceiver来处理接收的轨道
                try:
                    asyncio.ensure_future(video_receiver.handle_track(track))
                    log_success("远程视频轨道处理任务已启动")
                except Exception as e:
                    log_failure("启动远程视频轨道处理任务失败: {e}", e=e)
                    import traceback
                    traceback.print_exc()
            elif track.kind == "audio":
                log_success("开始处理接收的远程音频轨道（在本地播放）")
                # 使用AudioReceiver来处理接收的轨道
                try:
                    asyncio.ensure_future(audio_receiver.handle_track(track))
                    log_success("远程音频轨道处理任务已启动")
                except Exception as e:
                    log_failure("启动远程音频轨道处理任务失败: {e}", e=e)
                    import traceback
                    traceback.print_exc()
            else:
                log_info("收到未知轨道: {track_kind}", track_kind=track.kind)
        
        # 在连接建立后调用调试函数
        @pc.on("connectionstatechange")
        def on_connectionstatechange():
            nonlocal stats_task  # 声明使用外部变量
            log_connection("状态: {connection_state}", connection_state=pc.connectionState)
            if pc.connectionState == "connected":
                log_success("WebRTC双向连接已建立，开始双向视频传输")
                log_info("发送器数量: {senders_count}, 接收器数量: {receivers_count}", 
                        senders_count=len(pc.getSenders()), receivers_count=len(pc.getReceivers()))

                # 配置接收器FEC参数
                asyncio.create_task(configure_receivers_with_fec(pc, fec_controller))
                
                # 配置发送器FEC参数（在连接建立后）
                asyncio.create_task(configure_senders_with_fec(pc, fec_controller))
                
                # 调用调试函数
                #asyncio.ensure_future(debug_track_status())
                
                # 启动持续统计更新任务（减少频率以提高性能）
                if not stats_task or stats_task.done():
                    stats_task = asyncio.create_task(periodic_stats_update(pc))
            elif pc.connectionState == "failed":
                log_failure("WebRTC连接失败")
            elif pc.connectionState == "closed":
                log_connection("连接已关闭")
            elif pc.connectionState == "disconnected":
                log_connection("连接断开")
            elif pc.connectionState == "connecting":
                log_connection("正在建立双向连接...")

        async def periodic_stats_update(pc):
            log_info("periodic_stats_update 启动")
            
            # 记录上次统计时的累计数据，分别针对video和audio
            last_encode_stats = {
                "video": {"total_frames": 0, "total_time": 0.0},
                "audio": {"total_frames": 0, "total_time": 0.0},
            }
            last_decode_stats = {
                "video": {"total_frames": 0, "total_time": 0.0},
                "audio": {"total_frames": 0, "total_time": 0.0},
            }
            
            # 调试：检查发送者和接收者
            senders = pc.getSenders()
            receivers = pc.getReceivers()
            log_debug("发送者数量={senders_len}, 接收者数量={receivers_len}", senders_len=len(senders), receivers_len=len(receivers))
            
            try:
                while pc.connectionState == "connected" and not shutdown_event.is_set():
                    try:
                        current_time = time.time()
                        stats = await pc.getStats()
                        
                        # 收集统计信息
                        rtt_info = None
                        encode_info = {"video": None, "audio": None}
                        decode_info = {"video": None, "audio": None}
                        totals_info = {"video": {"enc": None, "dec": None}, "audio": {"enc": None, "dec": None}}
                        
                        for stat in stats.values():
                            # RTP往返时延
                            if stat.type == "remote-inbound-rtp" and stat.kind in ("video", "audio"):
                                rtt = getattr(stat, "roundTripTime", None)
                                if rtt is not None:
                                    rtt_info = f"RTP往返时延(RTT): {rtt*1000:.2f} ms"
                            # 编码时延统计 (outbound-rtp)
                            elif stat.type == "outbound-rtp" and stat.kind in ("video", "audio"):
                                if hasattr(stat, "totalFramesEncoded") and hasattr(stat, "totalEncodeTime"):
                                    kind = stat.kind
                                    current_total_frames = getattr(stat, "totalFramesEncoded", 0)
                                    current_total_time = getattr(stat, "totalEncodeTime", 0.0)
                                    # totals
                                    totals_info[kind]["enc"] = f"累计编码: 帧数 {current_total_frames}, 总时延 {current_total_time:.2f}ms"
                                    # 1s window
                                    if last_encode_stats[kind]["total_frames"] > 0:
                                        frames_in_1s = current_total_frames - last_encode_stats[kind]["total_frames"]
                                        time_in_1s = current_total_time - last_encode_stats[kind]["total_time"]
                                        if frames_in_1s > 0:
                                            avg_encode_time_1s = time_in_1s / frames_in_1s
                                            encode_info[kind] = f"发送编码 {kind}: 平均 {avg_encode_time_1s:.2f}ms, 帧数 {frames_in_1s}"
                                    last_encode_stats[kind]["total_frames"] = current_total_frames
                                    last_encode_stats[kind]["total_time"] = current_total_time

                            # 解码时延统计 (inbound-rtp)
                            elif stat.type == "inbound-rtp" and stat.kind in ("video", "audio"):
                                if hasattr(stat, "totalFramesDecoded") and hasattr(stat, "totalDecodeTime"):
                                    kind = stat.kind
                                    current_total_frames = getattr(stat, "totalFramesDecoded", 0)
                                    current_total_time = getattr(stat, "totalDecodeTime", 0.0)
                                    # totals
                                    totals_info[kind]["dec"] = f"累计解码: 帧数 {current_total_frames}, 总时延 {current_total_time:.2f}ms"
                                    # 1s window
                                    if last_decode_stats[kind]["total_frames"] > 0:
                                        frames_in_1s = current_total_frames - last_decode_stats[kind]["total_frames"]
                                        time_in_1s = current_total_time - last_decode_stats[kind]["total_time"]
                                        if frames_in_1s > 0:
                                            avg_decode_time_1s = time_in_1s / frames_in_1s
                                            decode_info[kind] = f"接收解码 {kind}: 平均 {avg_decode_time_1s:.2f}ms, 帧数 {frames_in_1s}"
                                    last_decode_stats[kind]["total_frames"] = current_total_frames
                                    last_decode_stats[kind]["total_time"] = current_total_time

                        # 统一显示统计信息（视频+音频）
                        log_info("=== 双向媒体流统计 (过去1秒) ===")
                        for kind in ("video", "audio"):
                            log_info("-- {kind} --", kind=kind)
                            if encode_info[kind]:
                                log_success("{encode_info}", encode_info=encode_info[kind])
                            else:
                                log_info("无编码统计数据")
                            if totals_info[kind]["enc"]:
                                log_info("  {totals_enc}", totals_enc=totals_info[kind]['enc'])
                            if decode_info[kind]:
                                log_success("{decode_info}", decode_info=decode_info[kind])
                            else:
                                log_info("无解码统计数据")
                            if totals_info[kind]["dec"]:
                                log_info("  {totals_dec}", totals_dec=totals_info[kind]['dec'])
                        
                        # 简化FEC统计信息输出（减少日志量以提高性能）
                        # fec_stats = fec_controller.get_stats()
                        # if fec_stats and any(fec_stats.values()):
                        #     log_fec("=======FEC统计=======")
                        #     log_fec("FEC包发送: {sent}, 接收: {received}", 
                        #            sent=fec_stats.get('fec_packets_sent', 0),
                        #            received=fec_stats.get('fec_packets_received', 0))
                        #     log_fec("修复包数: {repaired}, 丢失包数: {lost}", 
                        #            repaired=fec_stats.get('packets_repaired', 0),
                        #            lost=fec_stats.get('packets_lost', 0))
                        #     log_fec("修复成功率: {success_rate:.2%}", 
                        #            success_rate=fec_stats.get('repair_success_rate', 0.0))
                        
                        # 简化网络统计信息输出（减少日志量以提高性能）
                        # if rtt_info:
                        #     log_info("=======网络统计=======")
                        #     print(rtt_info)
                            
                    except Exception as e:
                        # 简化错误处理，减少日志输出以提高性能
                        if "closed" not in str(e).lower():
                            log_info("获取统计信息异常: {e}", e=e)
                        break
                    
                    # 检查是否需要关闭
                    if shutdown_event.is_set():
                        break
                        
                    await asyncio.sleep(1)  # 恢复统计更新频率
            except Exception as e:
                log_info("periodic_stats_update 异常: {e}", e=e)
                if "closed" not in str(e).lower():
                    import traceback
                    traceback.print_exc()
            finally:
                log_info("periodic_stats_update 结束")

        @pc.on("icecandidate")
        async def on_icecandidate(candidate):
            if candidate and not shutdown_event.is_set():
                try:
                    log_info("发送 ICE candidate: {candidate_info}", candidate_info=candidate.candidate)
                    await signaling.send_candidate(candidate)
                except Exception as e:
                    log_info("发送ICE candidate失败: {e}", e=e)

        @pc.on("icegatheringstatechange")
        async def on_icegatheringstatechange():
            log_connection("收集状态: {gathering_state}", gathering_state=pc.iceGatheringState)

        @pc.on("iceconnectionstatechange")
        async def on_iceconnectionstatechange():
            log_connection("连接状态: {ice_connection_state}", ice_connection_state=pc.iceConnectionState)
            if pc.iceConnectionState == "failed":
                log_connection("连接失败")
            elif pc.iceConnectionState == "disconnected":
                log_connection("连接断开")
            elif pc.iceConnectionState == "connected":
                log_connection("连接成功")
            elif pc.iceConnectionState == "checking":
                log_connection("正在检查连接...")
            elif pc.iceConnectionState == "completed":
                log_connection("连接检查完成")
                # 调试：ICE连接完成时的状态
                senders = pc.getSenders()
                receivers = pc.getReceivers()
                log_debug("ICE连接完成时 - 发送者数量={senders_count}, 接收者数量={receivers_count}", senders_count=len(senders), receivers_count=len(receivers))
            
            # 添加ICE连接状态监控
            log_connection("连接时间: {connection_time:.1f}s", connection_time=time.time() - start_time)

        @pc.on("signalingstatechange")
        async def on_signalingstatechange():
            log_connection("状态: {signaling_state}", signaling_state=pc.signalingState)

        # 连接到信令服务器
        log_progress("连接信令服务器...")
        await signaling.connect()
        log_info("已连接到信令服务器")
        
        # 网络诊断
        log_info("=== 网络诊断 ===")
        log_connection("服务器: {server_url}", server_url=server_url)
        log_connection("服务器: {ice_servers}", ice_servers=config.iceServers)
        log_info("本机ID: {client_id}, 对方ID: {peer_id}", client_id=client_id, peer_id=peer_id)
        log_info("==================")
        
        # 添加连接保持逻辑
        log_progress("保持连接...")

        if is_offering:
            log_info("作为发起方...")
            
            offer = await pc.createOffer()
            log_info("创建offer成功")
            # 设置本地描述
            await pc.setLocalDescription(offer)
            log_info("设置本地描述(offer)成功")
            # 发送 offer 给对方
            await signaling.send(pc.localDescription)
            log_info("offer已发送到信令服务器")
            # 等待接收 answer
            log_info("等待接收answer...")
            answer = await signaling.receive()
            if isinstance(answer, RTCSessionDescription):
                log_info("收到answer")
                await pc.setRemoteDescription(answer)
                log_info("设置远端描述(answer)成功")
        else:
            log_info("作为接收方...")
            log_info("等待接收offer...")
            offer = await signaling.receive()
            if isinstance(offer, RTCSessionDescription):
                log_info("收到offer")
                # 设置远端描述
                await pc.setRemoteDescription(offer)
                log_info("设置远端描述(offer)成功")
                
                # 创建 answer
                answer = await pc.createAnswer()
                log_info("创建answer成功")
                # 设置本地描述
                await pc.setLocalDescription(answer)
                log_info("设置本地描述(answer)成功")
                # 发送 answer 给对方
                await signaling.send(pc.localDescription)
                log_info("answer已发送到信令服务器")
        
        # 处理 ICE candidates
        log_progress("处理ICE candidates...")
        candidate_timeout = 30  # 30秒超时
        start_time_candidates = time.time()
        
        while pc.connectionState not in ["connected", "failed"] and not shutdown_event.is_set():
            try:
                # 设置超时
                if time.time() - start_time_candidates > candidate_timeout:
                    log_connection("candidates处理超时 ({candidate_timeout}秒)", candidate_timeout=candidate_timeout)
                    break
                    
                obj = await asyncio.wait_for(signaling.receive(), timeout=5.0)
                if isinstance(obj, RTCIceCandidate):
                    log_info("收到 ICE candidate: {candidate_info}", candidate_info=obj.candidate)
                    try:
                        await pc.addIceCandidate(obj)
                    except Exception as e:
                        log_info("添加ICE candidate失败: {e}", e=e)
                        if "closed" in str(e).lower():
                            break
                elif isinstance(obj, RTCSessionDescription):
                    try:
                        await pc.setRemoteDescription(obj)
                    except Exception as e:
                        log_info("设置远端描述失败: {e}", e=e)
                        if "closed" in str(e).lower():
                            break
            except asyncio.TimeoutError:
                log_info("等待ICE candidates超时，继续检查连接状态...")
                continue
            except Exception as e:
                log_info("处理ICE candidates时异常: {e}", e=e)
                if "closed" in str(e).lower():
                    break
                continue
        
        # 保持连接
        log_progress("保持连接...")
        connection_start_time = time.time()
        
        while pc.connectionState != "closed" and not shutdown_event.is_set():
            try:
                await asyncio.sleep(1)
                current_time = time.time()
                connection_duration = current_time - connection_start_time
                
                # 检查连接是否长时间无活动
                if connection_duration > 5 and pc.connectionState == "connected":
                    try:
                        stats = await pc.getStats()
                        has_activity = False
                        
                        for stat in stats.values():
                            if stat.type == "outbound-rtp" and hasattr(stat, "packetsSent"):
                                packets_sent = getattr(stat, "packetsSent", 0)
                                if packets_sent > 0:
                                    has_activity = True
                                    break
                            elif stat.type == "inbound-rtp" and hasattr(stat, "packetsReceived"):
                                packets_received = getattr(stat, "packetsReceived", 0)
                                if packets_received > 0:
                                    has_activity = True
                                    break
                        
                        if not has_activity:
                            log_warning("连接建立但未检测到数据传输")
                            # 检查是否有轨道
                            if hasattr(pc, 'getTransceivers'):
                                transceivers = pc.getTransceivers()
                                log_info("当前轨道数量: {transceivers_count}", transceivers_count=len(transceivers))
                                for i, transceiver in enumerate(transceivers):
                                    log_info("轨道 {index}: {mid} - {direction} - {current_direction}", 
                                            index=i, mid=transceiver.mid, direction=transceiver.direction, current_direction=transceiver.currentDirection)
                        
                        # 如果连接时间超过60秒，打印更多信息
                        if connection_duration > 60:
                            log_connection("已运行超过60秒，检查是否有数据传输...")
                            
                    except Exception as e:
                        if "closed" not in str(e).lower():
                            log_info("获取统计信息异常: {e}", e=e)
                        break
                        
            except Exception as e:
                log_info("保持连接时异常: {e}", e=e)
                if "closed" not in str(e).lower():
                    import traceback
                    traceback.print_exc()
                break

    except Exception as e:
        log_info("发生错误: {error_msg}", error_msg=str(e))
        import traceback
        traceback.print_exc()
        
    finally:
        log_info("关闭连接")
        try:
            # 停止统计任务
            if stats_task and not stats_task.done():
                stats_task.cancel()
                try:
                    await stats_task
                except asyncio.CancelledError:
                    pass
            
            # 关闭视频预览
            cv2.destroyAllWindows()
            if preview_manager:
                preview_manager.stop()
            
            
            # 关闭WebRTC连接
            if pc:
                await pc.close()
            
            # 关闭信令连接
            if signaling:
                await signaling.close()
                
        except Exception as e:
            log_info("关闭连接时异常: {e}", e=e)


from DeviceDiagnostics import test_camera, test_microphone, test_speaker

async def main():
    try:
        server_url = "wss://120.79.253.49:8765"
        is_offering = input("是否作为发起方? (y/n): ").lower() == 'y'
        client_id = input("输入本机ID: ").strip()
        peer_id = input("输入对方ID: ").strip()
        
        # 选择视频源：摄像头或视频文件
        log_info("\n选择视频源:")
        log_info("1. 摄像头 (输入摄像头ID，如: 0, 1, 2)")
        log_info("2. 视频文件 (输入文件路径)")
        log_info("3. 使用默认视频文件 (直接回车)")
        
        video_source = input("请输入摄像头ID、视频文件路径或直接回车使用默认文件: ").strip()
        
        if not video_source:
            # 使用默认视频文件
            video_source = "time.mp4"
        elif video_source.isdigit():
            # 使用摄像头，先测试摄像头
            camera_id = int(video_source)
            if not await test_camera(camera_id):
                print("摄像头测试失败，是否继续使用摄像头? (y/n): ", end="")
                if input().lower() != 'y':
                    log_info("将使用默认视频文件")
                    video_source = "time.mp4"
                else:
                    video_source = camera_id
            else:
                video_source = camera_id
        # 否则使用用户输入的文件路径

        # 选择FEC类型和参数
        display_fec_selection_menu()
        fec_choice = input("请选择FEC类型 (1-4, 默认1): ").strip()
        fec_type, fec_k, fec_n = parse_fec_choice(fec_choice)
        
        log_info("FEC配置: {fec_type}, k={k}, n={n}", 
                fec_type=fec_type or "禁用", k=fec_k, n=fec_n)

        # 启动前自检：根据视频源类型决定检查内容
        log_info("\n正在自检音频设备...")
        
        # 扬声器检查（接收音频播放需要）
        spk_ok = await test_speaker()
        log_info("扬声器: {status}", status='✓ 正常' if spk_ok else '✗ 不可用')
        
        # 麦克风检查（只在选择摄像头时需要）
        mic_ok = True  # 默认值
        if isinstance(video_source, int):  # 摄像头模式
            mic_ok = await test_microphone()
            log_info("麦克风: {status}", status='✓ 正常' if mic_ok else '✗ 不可用')
            if not mic_ok:
                print("检测到麦克风不可用（Linux 将优先尝试 ffmpeg 采集）。是否继续? (y/n): ", end="")
                if input().lower() != 'y':
                    log_info("已取消启动。")
                    return
        else:
            log_info("麦克风: 跳过检查（使用文件源）")
        
        if not spk_ok:
            print("检测到扬声器不可用/被占用。是否继续? (y/n): ", end="")
            if input().lower() != 'y':
                log_info("已取消启动。")
                return
        
        # 等待关闭信号
        await asyncio.gather(
            run_peer(is_offering, server_url, client_id, peer_id, video_source, fec_type, fec_k, fec_n),
            shutdown_event.wait()
        )
        
    except KeyboardInterrupt:
        log_info("\n收到中断信号，正在关闭...")
    except Exception as e:
        log_info("主程序异常: {e}", e=e)
        import traceback
        traceback.print_exc()
    finally:
        log_info("程序退出")

if __name__ == "__main__":
    asyncio.run(main())